package com.example.demo.util;

import com.alibaba.fastjson.JSONObject;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

/**
 * @Classname LocationJudgUtil
 * @Description 根据经纬度判断是否在某地区内
 * @Date 2019/8/7 11:17
 * @Created by yby
 */
public class LocationJudgUtil {

    private static final Logger logger = LoggerFactory.getLogger(LocationJudgUtil.class);

    private static final String key = "12344";
    /*
     *@Description 根据地址返回经纬度
     *@Param  [addr]
     *@return  java.lang.Object[]
     *@date  2019/8/7 13:53
     *@author  yby
     */
    public String[] getCoordinate(String addr) throws IOException{
        String lng = null;//经度
        String lat = null;//纬度
        String address = null;
        try {
            address = java.net.URLEncoder.encode(addr, "UTF-8");
        }catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        String key = "B8c99uLezWrx6UqP3e0I9AqfjzRZ95l9"; //f247cdb592eb43ebac6ccd27f796e2d2
        String src = "webapp.baidu.openAPIdemo88897974";
        String url = String .format("https://api.map.baidu.com/geocoder?address=%s&output=json&key=%s&src=%s", address, key,src);
        //String url="http://api.map.baidu.com/geocoder/v2/?ak=pmCgmADsAsD9rEXkqWNcTzjd&location=30.548397,104.04701&output=json&pois=1";
        URL myURL = null;
        URLConnection httpsConn = null;
        try {
            myURL = new URL(url);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        InputStreamReader insr = null;
        BufferedReader br = null;
        try {
            httpsConn = (URLConnection) myURL.openConnection();// 不使用代理
            if (httpsConn != null) {
                insr = new InputStreamReader( httpsConn.getInputStream(), "UTF-8");
                br = new BufferedReader(insr);
                String data = null;
                int count = 1;
                while((data= br.readLine())!=null){
                    if(count==5){
                        lng = (String)data.subSequence(data.indexOf(":")+1, data.indexOf(","));//经度
                        count++;
                    }else if(count==6){
                        lat = data.substring(data.indexOf(":")+1);//纬度
                        count++;
                    }else{
                        count++;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(insr!=null){
                insr.close();
            }
            if(br!=null){
                br.close();
            }
        }
        return new String[]{lng,lat};

    }


    public static String getAddress(String lng, String lat) {
        JSONObject obj = getLocationInfo(lat, lng).getJSONObject("result");
        StringBuilder address = new StringBuilder();
        String province = obj.getJSONObject("addressComponent").getString(
                "province");
        String city = obj.getJSONObject("addressComponent").getString("city");
        if (province != null && city != null && province.equals(city)) { 	//直辖市的省份名称和城市名称一样，判断重复时去掉
            address.append(
                    obj.getJSONObject("addressComponent").getString("city"))
                    .append(obj.getJSONObject("addressComponent").getString(
                            "district"))
                    .append(obj.getJSONObject("addressComponent").getString(
                            "street"))
                    .append(obj.getString("sematic_description"));
        } else {
            address.append(
                    obj.getJSONObject("addressComponent").getString("province"))
                    .append(obj.getJSONObject("addressComponent").getString(
                            "city"))
                    .append(obj.getJSONObject("addressComponent").getString(
                            "district"))
                    .append(obj.getJSONObject("addressComponent").getString(
                            "street"))
                    .append(obj.getString("sematic_description"));
        }

        return address.toString();
    }

    public static JSONObject getLocationInfo(String lat, String lng) {
        //String url = "http://api.map.baidu.com/geocoder/v2/?location=" + lat+ "," + lng+ "&output=json&ak=B8c99uLezWrx6UqP3e0I9AqfjzRZ95l9&pois=0";//旧版
        String url ="https://api.map.baidu.com/reverse_geocoding/v3/?ak=B8c99uLezWrx6UqP3e0I9AqfjzRZ95l9&output=json&src=webapp.baidu.openAPIdemo&coordtype=bd09ll&location=" + lat+ ","+lng;
        JSONObject obj = JSONObject.parseObject(HttpUtil.getRequest(url));
        System.out.println("\n"+"经纬度查询地址为：" + url);
        System.out.println("\n"+"经纬度坐标返回结果为：" + obj.toString());
        return obj;

    }
    public static String getCity(String lat, String lng,String type) {

        JSONObject obj = getLocationInfo(lat, lng).getJSONObject("result")
                .getJSONObject("addressComponent");
        String city="";
        switch (type){
            case "1":
                city = obj.getString("province");
            case "2":
                city =obj.getString("city");
            case "3":
                city =obj.getString("district");
        }
        return city;
    }

    private static double rad(double d) {
        //角度转换成弧度
        return d * Math.PI / 180.0;
    }

    private static final double EARTH_RADIUS = 6371393;// 地球半径,单位千米
    /**
     * 计算两个地点的距离
     *
     * @param lat1 第一个纬度
     * @param lng1 第一个经度
     * @param lat2 第二个纬度
     * @param lng2 第二个经度
     * @return 两个经纬度的距离
     */
    public static double getDistance(double lat1, double lng1, double lat2, double lng2) {
        double radLat1 = rad(lat1);//纬度
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;//两点纬度之差
        double b = rad(lng1) - rad(lng2);//经度之差

        //计算两点之间距离的公式
        double s = 2 * Math.asin(Math.sqrt(
                Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        //弧长乘地球半径（半径）
        s = s * EARTH_RADIUS;
        //精确距离的数值（单位千米）
        s = Math.round(s * 10000) / 10000;
        return s;

    }

    /**
     * 通过AB点经纬度获取距离
     *
     * @param pointA A点(经，纬)
     * @param pointB B点(经，纬)
     * @return 距离(单位：米)
     */
    public static double getDistance1(double lat1, double lng1, double lat2, double lng2) {
        // 经纬度（角度）转弧度。弧度用作参数，以调用Math.cos和Math.sin
        double radiansAX = Math.toRadians(lng1); // A经弧度
        double radiansAY = Math.toRadians(lat1); // A纬弧度
        double radiansBX = Math.toRadians(lng2); // B经弧度
        double radiansBY = Math.toRadians(lat2); // B纬弧度

        // cosβ1cosβ2cos（α1-α2）+sinβ1sinβ2
        double cos = Math.cos(radiansAY) * Math.cos(radiansBY) * Math.cos(radiansAX - radiansBX)
                + Math.sin(radiansAY) * Math.sin(radiansBY);
        double acos = Math.acos(cos); // 反余弦值
        return EARTH_RADIUS * acos; // 最终结果
    }


    /*
     *@Description 根据经纬度和地方判断是否在某个地方内  地方{省，市，区}
     *@Param  [lat, lng, place,type] type 1省 2市 3区/县
     *@return  boolean
     *@date  2019/8/7 15:40
     *@author  yby
     */
    public static boolean comparePlaceByParams(String lat,String lng,String place,String type){
       //判断参数
        if(null == lat || null == lng || null == place){
            logger.error("比较参数不能为空!");
            return false;
        }
        //首先根据经纬度找到所属地方信息
        JSONObject jsonObject = getLocationInfo(lat,lng);
        JSONObject result  = jsonObject.getJSONObject("result").getJSONObject("addressComponent");
        String province =result.getString("province");
        String city =result.getString("city");
        String district =result.getString("district");
        switch (type){
            case "1":
              if(place.equals(province))return true;
            case "2":
              if(place.equals(city))return true;
            case "3":
              if(place.equals(district))return true;
        }
        return false;
    }

    public static double getDistanceMeter(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid)
    {
        //创建GeodeticCalculator，调用计算方法，传入坐标系、经纬度用于计算距离
        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, gpsFrom, gpsTo);

        return geoCurve.getEllipsoidalDistance();
    }

    public static String formatDistance(double distance){
        System.out.println("key="+key);
        if(distance >1000){
            return  (double)Math.round(distance/1000*10)/10+"km";
        }else{
            return  Math.round(distance)+"m";
        }
    }


        public static void main(String[] args) throws IOException{

        //test1 根据地址获取经纬度
        LocationJudgUtil locationJudgUtil = new LocationJudgUtil();
        String[] o = locationJudgUtil.getCoordinate("永修县");
        System.out.println(o[0]);//经度 lnt
        System.out.println(o[1]);//纬度 lat
         String lng = o[0];//经度
         String lat = o[1];//纬度,
         lng = "120.042610"; //120.21937542
            lat = "30.304790"; //30.25924446
        //test2 根据经纬度获取地址
        System.out.println("经纬度具体地址为：" + locationJudgUtil.getAddress(lng,lat));
        //test3 根据经纬度获取区
            /*String area = getCity(o[1], o[0],"3");
            System.out.println("area="+area);
            //test4 判断经纬度是否在省市区/县 内
        boolean flag =locationJudgUtil.comparePlaceByParams(lat,lng,"永修县","3");
        System.out.println(flag);*/
            System.out.println("两点差距："+getDistance1(30.322138,120.064752,34.7519,113.666298));
            System.out.println("经纬度距离计算结果：" + getDistance(109.371319, 22.155406, 108.009758, 21.679011) + "米");


            GlobalCoordinates source = new GlobalCoordinates(30.322138, 120.064752);
            GlobalCoordinates target = new GlobalCoordinates(34.7519, 113.666298);

            double meter1 = getDistanceMeter(source, target, Ellipsoid.Sphere);
            double meter2 = getDistanceMeter(source, target, Ellipsoid.WGS84);

            System.out.println("Sphere坐标系计算结果："+meter1 + "米");
            System.out.println("WGS84坐标系计算结果："+meter2 + "米");

            System.out.println("格式化数据=="+formatDistance(358.4658896));

            System.out.println("key="+key);
    }

}
